package com.dcm.bargain.service.impl;

import com.dcm.bargain.entity.BargainEntity;
import com.dcm.bargain.entity.CutPriceEntity;
import com.dcm.bargain.mapper.BargainMapper;
import com.dcm.bargain.mapper.CutPriceMapper;
import com.dcm.bargain.service.CutPriceService;
import com.dcm.common.constant.Constants;
import com.dcm.common.exception.MyException;
import com.dcm.common.service.RedisService;
import com.dcm.common.vo.CommonResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * @author:zhouyuhan
 * 时间: 2021/3/27 15:34
 */
@Service
public class CutPriceServiceImpl implements CutPriceService {

    @Autowired
    private CutPriceMapper cutPriceMapper;

    @Autowired
    private BargainMapper bargainMapper;

    @Autowired
    private RedisService redisService;
    @Value("${redis.database}")
    private String redisDatabase;
    @Value("${redis.expire.common}")
    private Long redisExpire;
    @Value("${redis.key.bargain}")
    private String redisKeyBargain;
    /**
     * 发起砍价的具体逻辑
     * 当用户[uid]发起一个砍价，先使用getTempBargainList方法生成对应人数[sumNum-1]的砍价金额集合[avg,last]
     *
     * @param bid 商品id
     * @param uid 用户id
     */
    @Override
    public CommonResponse startBargain(Long bid, Long uid) {
        //砍价商品
        BargainEntity bargain = bargainMapper.echo(bid);
        //砍价记录 bid 商品id，uid 用户id,已砍次数,剩余次数,状态0：开启
        CutPriceEntity cutPriceEntity = new CutPriceEntity(uid, bid, 1, bargain.getCount()-1, new Date(),0);
        cutPriceEntity.setImages(bargain.getImages());
        cutPriceEntity.setProductName(bargain.getBargainName());
        //砍成的优惠价格 (原价 100 - 最低价 40 == 优惠价格 60)
        BigDecimal priceCut = bargain.getBargainPrice().subtract(bargain.getLowPrice());
        //初次砍价规则：自己首次砍价为总金额97% (60 * 0.97) 剩余 0.03
        priceCut = priceCut.multiply(new BigDecimal("0.03"));
        //剩余砍价金额
        cutPriceEntity.setPrice(priceCut);
        cutPriceEntity.setHelper(uid+"");
        List<BigDecimal> finalPrices = getTempBargainList(bargain.getCount(), priceCut);

        cutPriceMapper.insertCutPrice(cutPriceEntity);
        //添加后获得这条记录的主键id
        Long id = cutPriceEntity.getId();
        String key = redisDatabase + ":" + redisKeyBargain + ":" + id;
        redisService.set(key,finalPrices,redisExpire);
        return new CommonResponse(0,Constants.BargainErrorMsg.SUCCESS_BARGAIN);
    }
    /**
     * 帮助砍价 的 具体逻辑
     * 判断是否是最后一人 （判断是否已经砍过）
     * @param id 砍价id
     * @param uid 用户id
     */
    @Override
    public CommonResponse helpBargain(Long id, Long uid) {
        String key = redisDatabase + ":" + redisKeyBargain + ":" + id;
        List<BigDecimal> finalPrices = (List<BigDecimal>) redisService.get(key);

        CutPriceEntity cutPriceEntity = cutPriceMapper.findCutProduct(id);

        //判断订单状态
        if (cutPriceEntity.getStatus() == 1) {
            throw new MyException(Constants.BargainErrorMsg.CUT_FINISH);
        }
        //判断该用户是否已经砍过
        String[] users = cutPriceEntity.getHelper().split("-");
        for (String user : users) {
            if ((uid + "").equals(user)) {
                throw new MyException(Constants.BargainErrorMsg.REPEATED_BARGAIN);
            }
        }
        //使用Java并发包下AtomicInteger 保证 ++ -- 线程安全
        AtomicInteger sumNum = new AtomicInteger(cutPriceEntity.getSumNum());
        //加1
        sumNum.getAndIncrement();
        cutPriceEntity.setSumNum(sumNum.get());
        AtomicInteger remainNum = new AtomicInteger(cutPriceEntity.getRemainNum());
        //减1
        remainNum.getAndDecrement();
        cutPriceEntity.setRemainNum(remainNum.get());
        //helper 帮助砍价的人 通过拼接 uid 实现
        if (cutPriceEntity.getHelper() == null) {
            cutPriceEntity.setHelper(uid + "");
        } else {
            cutPriceEntity.setHelper(cutPriceEntity.getHelper() + "-" + uid);
        }

        //判断是否是最后一人(remainNum 为 0 剩余人数为 0)
        if (cutPriceEntity.getRemainNum() == 0) {
            //如果是最后一人 修改状态 关闭 1 砍价=》添加订单
            cutPriceEntity.setStatus(1);
            //使用 redis中 最后一人的砍价金额 last
            BigDecimal last = finalPrices.get(1);
            cutPriceEntity.setPrice(cutPriceEntity.getPrice().subtract(last));
            cutPriceMapper.updateCutPrice(cutPriceEntity);

            //删除redis中的砍价价格

            redisService.del(redisDatabase + ":" + redisKeyBargain + ":" + id + "");
            return new CommonResponse(0,Constants.BargainErrorMsg.LAST_SUCCESS+last,cutPriceEntity);

        } else {
            //使用 redis中 平均砍价数据
            BigDecimal last = finalPrices.get(0);
            cutPriceEntity.setPrice(cutPriceEntity.getPrice().subtract(last));
            cutPriceMapper.updateCutPrice(cutPriceEntity);
            return new CommonResponse(0,Constants.BargainErrorMsg.SUCCESS+last);
        }
    }

    /**
     * 获取价格集合
     *
     * @param count    预计砍成功人数
     * @param priceCut 自己砍一刀后的剩余价格
     * @return 平均值和最后一个砍价金额
     */
    private static List<BigDecimal> getTempBargainList(Integer count, BigDecimal priceCut) {
        //平均值
        BigDecimal avgPrice = priceCut.divide(new BigDecimal(count));
        // 把多余的小数点去掉
        avgPrice = avgPrice.setScale(2, RoundingMode.HALF_DOWN);

        return getPrices(count, avgPrice, priceCut);
    }

    /**
     * 获得砍价金额
     *
     * @param count    预计砍成功人数
     * @param avgPrice 平均
     * @param priceCut 砍价数额
     * @return 平均值和最后一个砍价金额
     */
    private static ArrayList<BigDecimal> getPrices(Integer count, BigDecimal avgPrice, BigDecimal priceCut) {
        ArrayList<BigDecimal> finalPrices = new ArrayList<>();
        //获得 最后 一个砍价人的 砍价数 subPrice
        BigDecimal price = avgPrice.multiply(new BigDecimal(count-2));
        BigDecimal subPrice = priceCut.subtract(price);
        //比较 subPrice 和 砍价平均值
        int i = subPrice.compareTo(avgPrice);
        //如果 subPrice 小与 平均值
        if (i <= 0) {
            //返回 这个平均值
            finalPrices.add(avgPrice);
            finalPrices.add(subPrice);
            return finalPrices;
        } else {
            //把平均值加 0.01 递归调用 getPrices方法
            BigDecimal increment = new BigDecimal("0.001");
            return getPrices(count, avgPrice.add(increment), priceCut);
        }
    }

    /**
     * 修改
     * @param id
     */
    @Override
    public void updateStatus(Long id) throws MyException{
        if(id==null){
            throw new MyException(Constants.BargainErrorMsg.BARGAIN_ID_CANNOT_NULL);
        }
        CutPriceEntity cutPriceEntity = cutPriceMapper.findCutProduct(id);
        Integer status = cutPriceEntity.getStatus();
        if(status==0){
            status=1;
            cutPriceMapper.updateStatus(status,id);
        }else if(status==1){
            status=0;
            cutPriceMapper.updateStatus(status,id);
        }
    }

    /**
     * 删除
     * @param id
     */
    @Override
    public void deleteStatus(Long id) throws MyException {
        if(id==null){
            throw new MyException(Constants.BargainErrorMsg.BARGAIN_ID_CANNOT_NULL);
        }else{
            CutPriceEntity cutPriceEntity = cutPriceMapper.findCutProduct(id);
            if(cutPriceEntity.getStatus()==1){
                cutPriceMapper.deleteStatus(id);
            }else{
                throw new MyException(Constants.BargainErrorMsg.NOTCUTFINISH);
            }
        }

    }

    /**
     * 根据id查询
     * @param id
     * @return
     */
    @Override
    public CutPriceEntity findCutProduct(Long id) throws MyException {
        if(id==null){
            throw new MyException(Constants.BargainErrorMsg.BARGAIN_ID_CANNOT_NULL);
        }
        return cutPriceMapper.findCutProduct(id);
    }




    /**
     *
     *
     * @param currentPage
     * @param pageSize
     * @param whichDay
     * @return
     */
    @Override
    public List<CutPriceEntity> findTime(Integer currentPage, Integer pageSize, String whichDay) throws MyException {

        if(Constants.Bargain.TODAY.equals(whichDay)){
            List<CutPriceEntity> cutPriceEntityList = cutPriceMapper.findTime(currentPage, pageSize,1);
            return cutPriceEntityList.stream().skip(pageSize * (currentPage - 1)).limit(pageSize).collect(Collectors.toList());
        }else if(Constants.Bargain.YESTERDAY.equals(whichDay)){
            List<CutPriceEntity> cutPriceEntityList = cutPriceMapper.findTime(currentPage, pageSize,2);
            return cutPriceEntityList.stream().skip(pageSize * (currentPage - 1)).limit(pageSize).collect(Collectors.toList());
        }else if(Constants.Bargain.SEVENDAYS.equals(whichDay)){
            List<CutPriceEntity> cutPriceEntityList = cutPriceMapper.findTime(currentPage, pageSize,3);
            return cutPriceEntityList.stream().skip(pageSize * (currentPage - 1)).limit(pageSize).collect(Collectors.toList());
        }else if(Constants.Bargain.THIRTYDAYS.equals(whichDay)){
            List<CutPriceEntity> cutPriceEntityList = cutPriceMapper.findTime(currentPage, pageSize,4);
            return cutPriceEntityList.stream().skip(pageSize * (currentPage - 1)).limit(pageSize).collect(Collectors.toList());
        }else if(Constants.Bargain.THISMONTH.equals(whichDay)){
            List<CutPriceEntity> cutPriceEntityList = cutPriceMapper.findTime(currentPage, pageSize,5);
            return cutPriceEntityList.stream().skip(pageSize * (currentPage - 1)).limit(pageSize).collect(Collectors.toList());
        }else if(Constants.Bargain.THISYEAR.equals(whichDay)){
            List<CutPriceEntity> cutPriceEntityList = cutPriceMapper.findTime(currentPage, pageSize,6);
            return cutPriceEntityList.stream().skip(pageSize * (currentPage - 1)).limit(pageSize).collect(Collectors.toList());
        }else if(isDateVail(whichDay)) {
            List<CutPriceEntity> cutPriceEntityList = cutPriceMapper.accurate(currentPage, pageSize, whichDay);
            return cutPriceEntityList.stream().skip(pageSize * (currentPage - 1)).limit(pageSize).collect(Collectors.toList());
        }else if(whichDay==null){
            List<CutPriceEntity> cutPriceEntityList = cutPriceMapper.accurate(currentPage, pageSize,  whichDay);
            return cutPriceEntityList.stream().skip(pageSize * (currentPage - 1)).limit(pageSize).collect(Collectors.toList());
        }else{
            throw new MyException(Constants.BargainErrorMsg.CANSHUGESHI);
        }

    }

    /**
     * 校验时间格式是否为 yyyy-MM-dd HH:mm:ss
     * @param date
     * @return
     */
    private static Boolean isDateVail(String date) {
        //用于指定 日期/时间 模式
        DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        boolean flag = true;
        try {
            //Java 8 新添API 用于解析日期和时间
            LocalDateTime.parse(date, dtf);
        } catch (Exception e) {
            flag = false;
        }
        return flag;
    }

}
